﻿Ext.data.AbstractStore = Ext.extend(Ext.util.Observable, {

    //如果为true，则把排序操作推迟到服务端执行。如果为false，在本地客户端进行排序。默认为false。
    remoteSort: false,

    //如果为true，则把过滤操作推迟到服务端执行。如果为false，在本地客户端进行过滤。默认为false。
    remoteFilter: false,

    //如果没有指定data，且autoLoad为true或一个对象，
    //则当前store的load方法会在store创建后自动调用
    //如果autoLoad是一个对象，该对象将作为参数传人store的load方法中
    autoLoad: false,      

    //True to automatically sync the Store with its Proxy after every edit to one of its Records. Defaults to false.
    autoSave: false,

    //下面是公共属性：

    //Sets the updating behavior based on batch synchronization(同步).
    batchUpdateMode: 'operation',

    //如果为true，任何与该Store关联的过滤器将在数据加载之后运行，默认为true。remoteFilter如果为true，该属性将被忽略
    filterOnLoad: true,

    //如果为true，任何与该Store关联的排序器将在数据加载之后运行，默认为true。remoteSort如果为true，该属性将被忽略
    sortOnLoad: true,

    //The default sort direction to use if one is not specified (defaults to "ASC")
    defaultSortDirection: "ASC",

    implicitModel: false,//是否包含了model，默认为false

    //The string type of the Proxy to create if none is specified. This defaults to creating a memory proxy.
    defaultProxyType: 'memory',

    //True if the Store has already been destroyed via destroyStore. If this is true, 
    //the reference to Store should be deleted as it will not function correctly any more.
    isDestroyed: false,

    isStore: true,

    constructor: function (config) {
        this.addEvents(
            'add',
            'remove',
            'update',
            'datachanged',
            'beforeload',
            'load',
            'beforesync'
        );

        Ext.apply(this, config);

        this.removed = [];

        //存储每个字段当前的排序方向（“ASC”或“DESC”）。用于在内部管理每个字段排序方向的切换。只读
        this.sortToggle = {};

        Ext.data.AbstractStore.superclass.constructor.apply(this, arguments);

        //通过model标识获取model类
        this.model = Ext.ModelMgr.getModel(config.model);


        Ext.applyIf(this, {
            modelDefaults: {}
        });

        //如果没有定义model，但定义了字段
        if (!this.model && config.fields) {
            //创建一个新的model类
            this.model = Ext.regModel('ImplicitModel-' + this.storeId || Ext.id(), {
                fields: config.fields
            });

            delete this.fields;

            this.implicitModel = true;//包含了model
        }

        //为当前Store设置代理，参数可以是字符串、配置对象或代理类实例
        this.setProxy(config.proxy || this.model.proxy);

        if (this.id && !this.storeId) {
            this.storeId = this.id;
            delete this.id;
        }

        if (this.storeId) {//根据storeId注册Store对象
            Ext.StoreMgr.register(this);
        }

        //排序对象集合
        this.sorters = new Ext.util.MixedCollection();

        //将sorters中的配置对象全部转换成Ext.util.Sorter对象,再放入this.sorters集合中
        this.sorters.addAll(this.decodeSorters(config.sorters));

        //筛选对象集合
        this.filters = new Ext.util.MixedCollection();

        //将filters中的配置对象全部转换成Ext.util.Filter对象,再放入this.filters集合中
        this.filters.addAll(this.decodeFilters(config.filters));
    },


    //为当前Store设置代理，参数可以是字符串、配置对象或代理类实例
    setProxy: function (proxy) {
        if (proxy instanceof Ext.data.Proxy) {//如果proxy是一个Ext.data.Proxy实例，则用它的setModel方法设置model对象

            proxy.setModel(this.model); //设置与代理相关的模型. 这个方法是提供给Store使用的
        } else {
            Ext.applyIf(proxy, {//如果proxy还只是一个配置对象，则把model对象添加到配置对象中，然后再创建proxy对象
                model: this.model
            });

            //创建代理对象
            proxy = Ext.data.ProxyMgr.create(proxy);
        }

        this.proxy = proxy;//包含代理对象

        return this.proxy;
    },

    //获取Store包含的代理对象
    getProxy: function () {
        return this.proxy;
    },

    // 创建模型实例
    create: function (data, options) {

        // 创建指定的model实例
        var instance = Ext.ModelMgr.create(Ext.applyIf(data, this.modelDefaults), this.model.modelName),
            operation;

        options = options || {};

        // model信息
        Ext.applyIf(options, {
            action: 'create',
            records: [instance]
        });

        // 操作对象
        operation = new Ext.data.Operation(options);

        // 代理的创建方法
        this.proxy.create(operation, this.onProxyWrite, this);

        return instance;
    },

    //读取数据
    read: function () {
        return this.load.apply(this, arguments);
    },

    onProxyRead: Ext.emptyFn,

    // 更新符合模型的记录
    update: function (options) {
        options = options || {};

        Ext.applyIf(options, {
            action: 'update',
            records: this.getUpdatedRecords()
        });

        // 操作对象
        var operation = new Ext.data.Operation(options);

        // 代理的更新方法
        return this.proxy.update(operation, this.onProxyWrite, this);
    },

    onProxyWrite: Ext.emptyFn,


    // 清除记录
    destroy: function (options) {
        options = options || {};

        Ext.applyIf(options, {
            action: 'destroy',
            records: this.getRemovedRecords()
        });

        // 操作对象
        var operation = new Ext.data.Operation(options);

        // 代理的清除方法
        return this.proxy.destroy(operation, this.onProxyWrite, this);
    },


    onBatchOperationComplete: function (batch, operation) {
        return this.onProxyWrite(operation);
    },


    onBatchComplete: function (batch, operation) {
        var operations = batch.operations,
            length = operations.length,
            i;

        this.suspendEvents();

        for (i = 0; i < length; i++) {
            this.onProxyWrite(operations[i]);
        }

        this.resumeEvents();

        this.fireEvent('datachanged', this);
    },

    onBatchException: function (batch, operation) {





    },


    filterNew: function (item) {
        return item.phantom == true || item.needsAdd == true;
    },


    getNewRecords: function () {
        return [];
    },


    getUpdatedRecords: function () {
        return [];
    },


    filterDirty: function (item) {
        return item.dirty == true;
    },


    getRemovedRecords: function () {
        return this.removed;
    },


    sort: function (sorters, direction) {

    },

    //将sorters中的配置对象全部转换成Ext.util.Sorter对象
    decodeSorters: function (sorters) {
        if (!Ext.isArray(sorters)) {//如果sorters不是数组形式，则把它转变成数组形式
            if (sorters == undefined) {
                sorters = [];
            } else {
                sorters = [sorters];
            }
        }

        var length = sorters.length,
            Sorter = Ext.util.Sorter,//排序类
            config, i;

        //为每个sorter配置对象生成一个Ext.util.Sorter实例
        for (i = 0; i < length; i++) {
            config = sorters[i];

            if (!(config instanceof Sorter)) {
                if (Ext.isString(config)) {//如果排序属性是字符串，则转变成对象形式
                    config = {
                        property: config
                    };
                }

                Ext.applyIf(config, {//配置数据根部和方向
                    root: 'data',
                    direction: "ASC"
                });


                if (config.fn) {//如果sorter对象设置了fn属性
                    config.sorterFn = config.fn;
                }


                if (typeof config == 'function') {//如果排序属性是一个函数，则转变成对象形式，并配置sorterFn属性
                    config = {
                        sorterFn: config
                    };
                }

                sorters[i] = new Sorter(config); //创建Ext.util.Sorter对象
            }
        }

        return sorters;
    },

    filter: function (filters, value) {

    },


    createSortFunction: function (field, direction) {
        direction = direction || "ASC";
        var directionModifier = direction.toUpperCase() == "DESC" ? -1 : 1;

        var fields = this.model.prototype.fields,
            sortType = fields.get(field).sortType;



        return function (r1, r2) {
            var v1 = sortType(r1.data[field]),
                v2 = sortType(r2.data[field]);

            return directionModifier * (v1 > v2 ? 1 : (v1 < v2 ? -1 : 0));
        };
    },

    //将filters中的配置对象全部转换成Ext.util.Filter对象
    decodeFilters: function (filters) {
        if (!Ext.isArray(filters)) {//如果filters不是数组形式，则把它转变成数组形式
            if (filters == undefined) {
                filters = [];
            } else {
                filters = [filters];
            }
        }

        var length = filters.length,
            Filter = Ext.util.Filter,//筛选类
            config, i;

        for (i = 0; i < length; i++) {
            config = filters[i];

            if (!(config instanceof Filter)) {//如果筛选属性不是Ext.util.Filter实例
                Ext.apply(config, {
                    root: 'data'//配置数据根部
                });


                if (config.fn) {//如果filter对象设置了fn属性
                    config.filterFn = config.fn;
                }


                if (typeof config == 'function') {//如果筛选属性是一个函数，则转变成对象形式，并配置filterFn属性
                    config = {
                        filterFn: config
                    };
                }

                filters[i] = new Filter(config); //创建Ext.util.Filter对象
            }
        }

        return filters;
    },

    clearFilter: function (supressEvent) {

    },

    isFiltered: function () {

    },

    filterBy: function (fn, scope) {

    },


    //将存储与其代理同步。这要求代理将存储中的任何新的、已更新的和已删除的记录一起批处理，在每个操作完成时更新存储的记录的内部表示。
    sync: function () {
        var me = this,
            options = {},
            toCreate = me.getNewRecords(),
            toUpdate = me.getUpdatedRecords(),
            toDestroy = me.getRemovedRecords(),
            needsSync = false;

        if (toCreate.length > 0) {
            options.create = toCreate;
            needsSync = true;
        }

        if (toUpdate.length > 0) {
            options.update = toUpdate;
            needsSync = true;
        }

        if (toDestroy.length > 0) {
            options.destroy = toDestroy;
            needsSync = true;
        }

        if (needsSync && me.fireEvent('beforesync', options) !== false) {
            // 批处理创建、更新、移除操作
            me.proxy.batch(options, me.getBatchListeners());
        }
    },


    // 代理对象的批处理响应函数
    getBatchListeners: function () {
        var listeners = {
            scope: this,
            exception: this.onBatchException
        };

        if (this.batchUpdateMode == 'operation') {
            listeners['operationcomplete'] = this.onBatchOperationComplete;
        } else {
            listeners['complete'] = this.onBatchComplete;
        }

        return listeners;
    },


    save: function () {
        return this.sync.apply(this, arguments);
    },

    //加载数据
    load: function (options) {
        var me = this,
            operation;

        options = options || {};

        Ext.applyIf(options, {
            action: 'read',
            filters: me.filters.items,//筛选信息
            sorters: me.sorters.items//分组信息
        });

        operation = new Ext.data.Operation(options);//操作类

        if (me.fireEvent('beforeload', me, operation) !== false) {
            me.loading = true; //表示已经加载了数据
            //Reads data from the configured data object. Uses the Proxy's reader, if present
            me.proxy.read(operation, me.onProxyLoad, me); //Ext.data.MemoryProxy的方法
        }

        return me;
    },


    afterEdit: function (record) {
        this.fireEvent('update', this, record, Ext.data.Model.EDIT);
    },


    afterReject: function (record) {
        this.fireEvent('update', this, record, Ext.data.Model.REJECT);
    },


    afterCommit: function (record) {
        if (this.autoSave) {
            this.sync();
        }

        this.fireEvent('update', this, record, Ext.data.Model.COMMIT);
    },

    clearData: Ext.emptyFn,

    destroyStore: function () {
        if (!this.isDestroyed) {
            if (this.storeId) {
                Ext.StoreMgr.unregister(this);
            }
            this.clearData();
            this.data = null;
            this.tree = null;

            this.reader = this.writer = null;
            this.clearListeners();
            this.isDestroyed = true;

            if (this.implicitModel) {
                Ext.destroy(this.model);
            }
        }
    },


    getSortState: function () {
        return this.sortInfo;
    },

    getCount: function () {

    },

    getById: function (id) {

    },



    removeAll: function () {

    }
});